package TetrisGame;

import User.ScoreBoard;
import Shift.Father;
import Shift.move;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Stack;
import java.util.stream.IntStream;

public class Logic extends JPanel
{
    private String currentUser;
    private ScoreBoard scoreBoard = new ScoreBoard();
    private Father now = Father.randomOne(); //正在下落的方块
    private Father next = Father.randomOne(); //将要下落的方块
    private move[][] wall = new move[18][9]; //游戏主区域
    private static final int CELL_SIZE = 48; //声明单元格的值
    int[] scores_pool = {0, 1, 2, 5, 10}; //游戏分数池
    private int totalScore = 0; //当前游戏的分数
    private int totalLine = 0; //当前消除的行数
    //游戏三种状态 游戏中、暂停、结束
    public static final int PLING = 0;
    public static final int STOP = 1;
    public static final int OVER = 2;
    private int game_state; //当前游戏状态值
    String[] show_state = {"P[暂停游戏]", "C[继续游戏]", "S[重新开始]"}; //显示游戏状态
    //载入方块图片
    public static BufferedImage A;
    public static BufferedImage B;
    public static BufferedImage C;
    public static BufferedImage D;
    public static BufferedImage E;
    public static BufferedImage F;
    public static BufferedImage G;
    public static BufferedImage ui;

    private Stack<TetrisState> undoStack = new Stack<>();

    public void setCurrentUser(String username) {
        this.currentUser = username;
    }

    static
    {
        try
        {
            A = ImageIO.read(new File("images/A.png"));
            B = ImageIO.read(new File("images/B.png"));
            C = ImageIO.read(new File("images/C.png"));
            D = ImageIO.read(new File("images/D.png"));
            E = ImageIO.read(new File("images/E.png"));
            F = ImageIO.read(new File("images/F.png"));
            G = ImageIO.read(new File("images/G.png"));
            ui = ImageIO.read(new File("images/ui.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void paint(Graphics g)
    {
        g.drawImage(ui, 0, 0, null);
        g.translate(22, 15); //平移坐标轴
        paintWall(g); //绘制游戏主区域
        paintNow(g); //绘制正在下落的四方格
        paintNext(g); //绘制下一个将要下落的四方格
        paintScore(g); //绘制游戏得分
        paintCondi(g); //绘制当前游戏状态
    }
    private void paintWall(Graphics g)
    {
        for (int i = 0; i < wall.length; i++)
        {
            for (int j = 0; j < wall[i].length; j++)
            {
                int x = j * CELL_SIZE;
                int y = i * CELL_SIZE;
                move cell = wall[i][j];
                //判断是否有小方块
                if (cell == null)
                    g.drawRect(x, y, CELL_SIZE, CELL_SIZE);
                else
                    g.drawImage(cell.getImage(), x, y, null);
            }
        }
    }
    private void paintNow(Graphics g)
    {
        move[] cells = now.cells;
        for (move cell : cells)
        {
            int x = cell.getCol() * CELL_SIZE;
            int y = cell.getRow() * CELL_SIZE;
            g.drawImage(cell.getImage(), x, y, null);
        }
    }
    private void paintNext(Graphics g)
    {
        move[] cells = next.cells;
        for (move cell : cells)
        {
            int x = cell.getCol() * CELL_SIZE + 370;
            int y = cell.getRow() * CELL_SIZE + 25;
            g.drawImage(cell.getImage(), x, y, null);
        }
    }
    private void paintScore(Graphics g)
    {
        g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 30));
        g.drawString("分数: " + totalScore, 500, 250);
        g.drawString("行数: " + totalLine, 500, 430);
    }
    public void paintCondi(Graphics g)
    {
        if (game_state == PLING)
        {
            g.drawString(show_state[PLING], 500, 660);
        }
        else if (game_state == STOP)
        {
            g.drawString(show_state[STOP], 500, 660);
        }
        else
        {
            g.drawString(show_state[OVER], 500, 660);
            g.setColor(Color.RED);
            g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 60));
            g.drawString("GAME OVER!", 30, 400);
        }
    }

    public void start()
    {
        game_state = STOP; //初始状态为暂停，等待用户输入用户名
        undoStack.clear(); //清空撤销栈
        KeyListener l = new KeyAdapter()
        {
            @Override
            public void keyPressed(KeyEvent e)
            {
                int code = e.getKeyCode();
                if (game_state == PLING)
                {
                    switch (code)
                    {
                        case KeyEvent.VK_DOWN:
                            sortDropActive();
                            break;
                        case KeyEvent.VK_LEFT:
                            moveleftActive();
                            break;
                        case KeyEvent.VK_RIGHT:
                            moveRightActive();
                            break;
                        case KeyEvent.VK_UP:
                            rotateRightActive();
                            break;
                        case KeyEvent.VK_SPACE:
                            hadnDropActive();
                            break;
                        case KeyEvent.VK_R:
                            if (!undoStack.isEmpty())
                                undo();
                            break;
                    }
                }
                if (code == KeyEvent.VK_P)
                {
                    if (game_state == PLING)
                        game_state = STOP;
                    else if (game_state == STOP)
                        game_state = PLING;
                }
                if (code == KeyEvent.VK_C)
                    if (game_state == STOP)
                        game_state = PLING;
                if (code == KeyEvent.VK_S)
                {
                    game_state = PLING;
                    wall = new move[18][9];
                    now = Father.randomOne();
                    next = Father.randomOne();
                    totalScore = 0;
                    totalLine = 0;
                }
            }
        };
        addKeyListener(l);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
        requestFocus();
        while (true)
        {
            if (game_state == PLING)
            {
                try {
                    Thread.sleep(400);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (camDrop())
                    now.moveDrop();
                else
                {
                    landToWallAndPrepareNext();
                    destroyLine();
                    if (isGameOver())
                    {
                        game_state = OVER;
                        gameOver();
                    }
                    else
                    {
                        now = next;
                        next = Father.randomOne();
                    }
                }
            }
            repaint();
        }
    }

    class TetrisState
    {
        Father now;
        Father next;
        move[][] wall;
        int totalScore;
        int totalLine;
        public TetrisState(Father now, Father next, move[][] wall, int totalScore, int totalLine)
        {
            this.now = new Father(now); // 假设 Father 类有复制构造函数
            this.next = new Father(next); // 同上
            this.wall = deepCopyOfWall(wall); // 深拷贝墙壁状态
            this.totalScore = totalScore;
            this.totalLine = totalLine;
        }
        private move[][] deepCopyOfWall(move[][] original) //深拷贝墙壁状态
        {
            move[][] copy = new move[original.length][];
            for (int i = 0; i < original.length; i++)
            {
                copy[i] = new move[original[i].length];
                for (int j = 0; j < original[i].length; j++)
                {
                    if (original[i][j] != null)
                        copy[i][j] = new move(original[i][j].getRow(), original[i][j].getCol(), original[i][j].getImage());
                    else
                        copy[i][j] = null;
                }
            }
            return copy;
        }
    }

    private void undo()
    {
        if (undoStack.size() > 1) //检查撤销栈是否有足够的元素进行撤销操作
        {

            TetrisState currentState = undoStack.pop(); //弹出当前状态
            TetrisState previousState = undoStack.pop(); //弹出前一个状态并恢复
            restoreState(previousState);
            undoStack.push(currentState); //将当前状态重新压入栈，以便后续可能的再次撤销
        } else
        {
            //给出提示信息，告知用户无法进行撤销操作
            JOptionPane.showMessageDialog(this, "无法进行撤销操作，撤销栈元素不足！", "撤销失败", JOptionPane.WARNING_MESSAGE);
        }
    }
    private void restoreState(TetrisState state)
    {
        now = state.now;
        next = state.next;
        wall = state.wall;
        totalScore = state.totalScore;
        totalLine = state.totalLine;
        repaint(); //重绘游戏界面
    }

    public void gameOver()
    {
        if (now != null)
        {
            scoreBoard.addScore(currentUser, totalScore); // 传递 currentUser
            int option = JOptionPane.showConfirmDialog(this, "是否继续游戏？", "游戏结束", JOptionPane.YES_NO_OPTION);
            if (option == JOptionPane.YES_OPTION)
            {
                game_state = PLING;
                wall = new move[18][9];
                now = Father.randomOne();
                next = Father.randomOne();
                totalScore = 0;
                totalLine = 0;
            }
            else
                System.exit(0);
        }
        else
        {
            System.out.println("Error: Current user is null");
            System.exit(1); // 退出程序，因为当前用户是 null
        }
    }

    //创建顺时针旋转
    public void rotateRightActive()
    {
        now.rotateRight();
        if (outOFBounds() || coincide())
        {
            now.rotateLeft();
        }
    }

    //瞬间下落
    public void hadnDropActive()
    {
        while (true) {
            if (camDrop()) //判断能否下落
                now.moveDrop();
            else break;
        }
        //嵌入到墙中
        landToWallAndPrepareNext();
        //destroyLine();
        if (isGameOver())
            game_state = OVER;
        else {
            //游戏没有结束
            now = next;
            next = Father.randomOne();
        }
    }

    // 按键一次，下落一格
    public void sortDropActive()
    {
        if (camDrop())
            now.moveDrop(); //当前四方格下落一格
        else
        {
            landToWallAndPrepareNext(); //落下并固定到墙壁上，准备下一个方块
            //destroyLine();
            if (isGameOver())
                game_state = OVER;
            else
            {
                now = next;
                next = Father.randomOne();
            }
        }
    }

    //在方块落下并嵌入墙壁后保存状态，并准备下一个方块
    public void landToWallAndPrepareNext()
    {
        move[] cells = now.cells;
        for (move cell : cells)
        {
            int row = cell.getRow();
            int col = cell.getCol();
            wall[row][col] = cell;
        }
        // 保存状态到撤销栈
        undoStack.push(new TetrisState(now, next, wall, totalScore, totalLine)); //注意这里传递的是wall,而不是deepCopyOfWall(wall)
        destroyLine();
        resetNowPosition(); //重置当前方块位置到起始位置
    }

    //重置当前方块位置到起始位置
    private void resetNowPosition()
    {
        for (move cell : now.cells)
        {
            cell.setRow(0); //设置初始行
            cell.setCol(4); //设置初始列，这里假设游戏区域宽度为9，中间列为4
        }
    }

    //判断四方格能否下落
    public boolean camDrop()
    {
        move[] cells = now.cells;
        for (move cell : cells)
        {
            int row = cell.getRow();
            int col = cell.getCol();
            //判断是否到达底部
            if (row == wall.length - 1)
                return false;
            else if (wall[row + 1][col] != null)
                return false;
        }
        return true;
    }

    //消除行
    public void destroyLine()
    {
        boolean[] fullLines = new boolean[wall.length];
        Arrays.fill(fullLines, false);
        // 先标记所有满行
        for (int i = 0; i < wall.length; i++)
        {
            if (isFullLine(i))
                fullLines[i] = true;
        }
        //处理满行的下移和清空操作
        for (int i = 0; i < wall.length; i++)
        {
            if (fullLines[i])
            {
                for (int j = i; j > 0; j--)
                    System.arraycopy(wall[j - 1], 0, wall[j], 0, wall[0].length);
                wall[0] = new move[wall[0].length];
                totalLine++;
            }
        }
        //根据消除的行数更新分数
        int linesEliminated = (int) IntStream.range(0, fullLines.length)
                .filter(i -> fullLines[i])
                .count();
        totalScore += scores_pool[linesEliminated];
    }

    //判断当前行是否已经满了
    public boolean isFullLine(int row)
    {
        move[] cells = wall[row];
        for (move cell : cells)
        {
            if (cell == null)
                return false;
        }
        return true;
    }

    //判断游戏是否结束
    public boolean isGameOver()
    {
        move[] cells = next.cells;
        for (move cell : cells)
        {
            int row = cell.getRow();
            int col = cell.getCol();
            if (wall[row][col] != null)
                return true;
        }
        return false;
    }

    //判断是否出界
    public boolean outOFBounds()
    {
        move[] cells = now.cells;
        for (move cell : cells)
        {
            int col = cell.getCol();
            int row = cell.getRow();
            if (row < 0 || row > wall.length - 1 || col < 0 || col > wall[0].length-1)
            {
                return true;
            }
        }
        return false;
    }

    //按键一次，左移一次
    public void moveleftActive()
    {
        now.moveLeft();
        //判断是否越界或重合
        if (outOFBounds() || coincide())
            now.moveRight();
    }

    //按键一次，右移一次
    public void moveRightActive()
    {
        now.moveRight();
        if (outOFBounds() || coincide()) //判断是否越界或重合
            now.moveLeft();
    }

    //判断是否重合
    public boolean coincide()
    {
        move[] cells = now.cells;
        for (move cell : cells)
        {
            int row = cell.getRow();
            int col = cell.getCol();
            if (wall[row][col] != null)
                return true;
        }
        return false;
    }

}
